package org.demo.szml.userservice.aop.aspect;

import io.jsonwebtoken.lang.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.demo.szml.eventtype.converter.logging.LoggingEventDetailConverter;
import org.demo.szml.eventtype.event.logging.LoggingEvent;
import org.demo.szml.userservice.aop.annotation.LoggableAction;
import org.demo.szml.userservice.config.SnowflakeIdConfiguration;
import org.demo.szml.userservice.controller.dto.UserBaseDTO;
import org.demo.szml.userservice.producer.LoggingMessageProducer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
 * @description: 日志处理切面
 * @date: 2025/6/20 10:09
 * @version: 1.0
 */
@Aspect
@Order(Ordered.LOWEST_PRECEDENCE)
@Component
public class LoggingHandleAspect {

    private final LoggingMessageProducer loggingMessageProducer;

    private final SnowflakeIdConfiguration snowflakeIdConfiguration;

    private final Tracer tracer;

    public LoggingHandleAspect(LoggingMessageProducer messageProducer,
                               SnowflakeIdConfiguration snowflakeIdConfiguration,
                               Tracer tracer){
        this.loggingMessageProducer = messageProducer;
        this.snowflakeIdConfiguration = snowflakeIdConfiguration;
        this.tracer = tracer;
    }

    @Around("@annotation(loggableAction)")
    public Object aroundNeedLogging(ProceedingJoinPoint joinPoint, LoggableAction loggableAction) throws Throwable {
        //获取请求参数
        Object[] args = joinPoint.getArgs();
        List<Object> requestArgs = args.length > 0 && loggableAction.logArgs() ? Arrays.asList(args) : Collections.emptyList();

        //设置操作状态
        int success = 1;
        String action = loggableAction.actionType();

        //执行原方法
        Object response = null;
        Object responseArg = loggableAction.logResult() ? response : "";
        try{
            response = joinPoint.proceed();
        }  catch (Throwable e) {
            success = 0;
            throw e;
        } finally{
            //发送日志消息
            String ip = "UNKNOWN";
            Long operatorId = -1L;
            if(args.length > 0 && args[0] instanceof UserBaseDTO){
                ip = ((UserBaseDTO)args[0]).getClientIp();
                operatorId = ((UserBaseDTO)args[0]).getOperatorId();
            }
            String traceId = Optional.ofNullable(tracer)
                    .map(Tracer::currentSpan)
                    .map(span -> span.context().traceId())
                    .orElse("no-active-trace");
            LoggingEvent.LoggingEventInfo build = LoggingEvent.LoggingEventInfo.builder().ip(ip)
                    .action(action).detail(LoggingEventDetailConverter.buildLoggingDetail(requestArgs, Collections.singletonList(responseArg),traceId))
                    .userId(operatorId).statusCode(success).logId(snowflakeIdConfiguration.snowflake.nextId()).build();
            loggingMessageProducer.sendLoggingMessage(build);
        }
        return response;
    }
}
